#include "Matrix.h"
#include <iostream>
#include <vector>


using namespace std;

int main(){
	// Matricies for input are located in the matrices file inside of the build directory	
	Matrix matrixA("4by4.max");
	Matrix matrixB("4by4.max");
	cout << "matrixA is:"<<endl;
	cout << matrixA << endl;

    if( matrixA.isSquare() ){
        cout << "matrixA is square" <<endl;
    }

	cout<< "The Trace of matrixA is: " << matrixA.trace() <<endl<<endl;
	/*
	vector<vector<double> > input;
	for (int i = 0; i < 2; i++){
		for (int j = 0; j < 3; j++){
			input.at(i).at(j) = i+j;
		}
	}
	*/


	/*cout << "Transpose of A is: " << endl;
	cout << matrixA.transpose() << endl;

	cout << "Negative of A is:" << endl;
	matrixA = -matrixA;
	cout << matrixA << endl; 
	

	cout << "Identity: " << endl << Matrix::identity(10) << endl;



	
		//Testing Scalar
	double Scal;
	do{
		Matrix matrixA("3by3.max");
		cout << "Enter scalar Value or -99 to exit:";
		cin >> Scal;
		cout <<"matrixA scaled by "<<Scal<<" is:"<< endl;
		matrixA = Scal*matrixA;
		cout << matrixA<< endl;
	}while(Scal != -99);
	
	
	// Testing Power
	int power;
	do{
		cout << "Enter Power value or -100 to exit:";
		cin >> power;
		cout <<"matrix is: "<< endl;
		cout << matrixA.Mpow(power) << endl;
	}while(power!= -100);

	cout << "Determinant of A is: " << matrixA.determinant() << endl;


	cout << "inverse of A is:" << endl;
	cout << matrixA.inverse() << endl;

	
	//cout << "Determinant of matrixA is: " << matrixA.determinant() << endl;

	//cout << matrixA.identity(20) << endl;

	// Every matrix has 3 data members, the number of rows, the number of columns (both ints), and the elements. 
	// This elements are represented as a vector<vector<double> >, and can be access with the operator() parameter.
	// For instance, if you want to print the element in row 1 and column 3 of matrixA you would say:
	//std::cout << matrixA(1,3);

	// this will be the operator+ method
	Matrix matrixC = matrixA + matrixB;

    //Matrix matrixD(3, 4); should make an assertion fail
   // cout << matrixC + matrixD;
   //
    cout << "The sum of matrixA + matrixB is:" << endl;
	cout << matrixC <<endl;

    cout << "The difference of matrixC - matrixA is:" << endl;
	cout << matrixC - matrixA <<endl;*/

	cout << "Echelon form:"<< endl;
	cout <<matrixA.echelon()<<endl;

	cout << "L factorization:"<< endl;
	cout <<matrixA.Lfact()<<endl;

	cout << "U factorization:"<< endl;
	cout <<matrixA.Ufact()<<endl;

	cout << "LU"<< endl;
	cout <<matrixA.Lfact()*matrixA.Ufact()<<endl;

	cout << "Q factorization:"<< endl;
	cout <<matrixA.Qfact()<<endl;

	cout << "R factorization:"<< endl;
	cout <<matrixA.Rfact()<<endl;

    if(matrixA == matrixA) {
        cout << "== works" << endl;
    }
    else{
        cout << "== doesn't work" << endl;
    }

    /*if(matrixA != matrixC) {
        cout << "!= works" << endl;
    }
    else{
        cout << "!= doesn't work" << endl;
    }
	*/
	// this will be the operator* method
	//matrixC = matrixA * matrixB;

	// this will be the invert() method
	//matrixC = matrixA.invert();

	// this will be the determinant method
	//int result = matrixA.determinant();
	
	// All of these operations will be added to the Matrix.h and Matrix.cpp files. Thus the private datamembers will be available,
	// and you could access the elements by saying: matrixA.elements->at(i).at(j) or matrixA.elements[i][j] or matrixA(i,j)
	
   // cout << matrixA;
    
	return 0;
}
